<template>
	<view class="com-swiper-action position-relative">
		<view class="position-absolute top-0 bottom-0 left-0 y-flex y-row" ref="leftMenu">
			<view class="pl-20 pr-20 y-flex y-justify-center" :class="'bg-'+item.type" :style="{'background-color': item.color}"
			v-for="(item, index) in leftData" :key="index" @tap="handleLeftMenuTap(index)">
				<text class="fs-28 fr-fff pl-20 pr-20">{{item.label}}</text>
			</view>	
		</view>
		<view class="position-absolute top-0 bottom-0 right-0 y-flex y-row" ref="rightMenu">
			<view class="pl-20 pr-20 y-flex y-justify-center" :class="'bg-'+item.type" :style="{'background-color': item.color}"
			v-for="(item, index) in rightData" :key="index" @tap="handleRightMenuTap(index)">
				<text class="fs-28 fr-fff pl-20 pr-20">{{item.label}}</text>
			</view>	
		</view>
		<view class="y-flex" ref="comSwiperActionContent" :style="{'background-color': bgColor, 'transform': 'translateX(' + translateX + ')'}"
		@horizontalpan="touchstart"
		@tap="handleTap">
			<slot></slot>
		</view>
	</view>
</template>

<script>
	const Binding = uni.requireNativePlugin('bindingx')
	const animation = uni.requireNativePlugin('animation')
	const dom = uni.requireNativePlugin('dom')
	export default {
		props: {
			leftData: {
				type: Array,
				default: () => []
			},
			rightData: {
				type: Array,
				default: () => []
			},
			bgColor: {
				type: String,
				default: '#fff'
			},
			//动画时间
			duration: {
				type: Number,
				default: 300
			},
			//菜单改变触发阙值
			threshold: {
				type: Number,
				default: 20
			},
			//禁用菜单
			disabled: {
				type: Boolean,
				default: false
			},
			//菜单点击后自动关闭
			autoClose: {
				type: Boolean,
				default: true
			}
		},
		computed: {
			translateX () {
				return this.state == 'right' ? -this.rightMenuSize.width + 'px' : this.state == 'left' ? this.leftMenuSize.width + 'px' : 0
			}
		},
		beforeDestroy () {
			if ( this.swiperBinding ) {
				Binding.unbind({
					token: this.swiperBinding.token,
					eventType: 'pan'
				})
				this.swiperBinding = null
			}
		},
		data () {
			return {
				leftMenuSize: null,//左边菜单尺寸
				rightMenuSize: null,//右边菜单尺寸
				state: '',//状态
				loading: false//执行动画状态
			}
		},
		methods: {
			async updateSize () {
				this.leftMenuSize = await this.getRect(this.$refs.leftMenu)
				this.rightMenuSize = await this.getRect(this.$refs.rightMenu)
			},
			async touchstart (event) {
				if ( this.disabled ) return
				if ( this.swiperBinding ) return
				if ( this.loading ) return
				if ( this.state ) {
					this.closeMenu()
					return
				}
				if ( !this.leftMenuSize ) this.leftMenuSize = await this.getRect(this.$refs.leftMenu)
				if ( !this.rightMenuSize ) this.rightMenuSize = await this.getRect(this.$refs.rightMenu)
				//获取元素的初始位置，因为考虑到滑动菜单可能处于打开的状态
				this.swiperBinding = Binding.bind({
					anchor: this.getEl('comSwiperActionContent'),
					eventType: 'pan',
					props: [{
						element: this.getEl('comSwiperActionContent'),
						property: 'transform.translateX',
						// x小于0表示向左滑动，x>0表示向右滑动
						expression: `x < 0 ? (abs(x) > ${this.rightMenuSize.width} ? -${this.rightMenuSize.width} : x+0) : (x > ${this.leftMenuSize.width} ? ${this.leftMenuSize.width} : x+0)`
					}]
				}, (e) => {
					if ( ['end', 'cancel'].includes(e.state) && this.swiperBinding) {
						Binding.unbind({
							token: this.swiperBinding.token,
							eventType: 'pan'
						})
						this.swiperBinding = null
						let state = ''
						//如果移动距离小于0表示向左滑动，移动距离大于阙值，则显示右边菜单
						if ( e.deltaX < 0 && Math.abs(e.deltaX) > this.threshold ) state = 'right'
						//如果移动距离大于0表示向右滑动，移动距离大于阙值，则显示右边菜单
						else if ( e.deltaX > 0 && e.deltaX > this.threshold ) state = 'left'
						else state = ''
						const offset = state == 'right' ? -this.rightMenuSize.width + 'px' : state == 'left' ? this.leftMenuSize.width + 'px' : 0
						this.loading = true
						//重置移动距离为0需要调用animation，因为元素的translateX默认其实是0，bindingX不会改变节点的translateX，所以设置为0不会触发动画
						animation.transition(this.getRef('comSwiperActionContent'), {
							styles: {
								transform: `translateX(${offset})`
							},
							duration: this.duration,
							needLayout: true
						}, () => {
							this.state = state
							this.loading = false
						})
					}
				})
			},
			closeMenu () {
				this.loading = true
				animation.transition(this.getRef('comSwiperActionContent'), {
					styles: {
						transform: 'translateX(0)'
					},
					duration: this.duration,
					needLayout: true
				}, () => {
					this.state = ''
					this.loading = false
				})
			},
			getEl (selector) {
				const el = this.$refs[selector] && this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector]
				if ( !el ) return null
				if (typeof el === 'string' || typeof el === 'number') return el;
				if (WXEnvironment) {
				    return el.ref;
				} else {
				    return el instanceof HTMLElement ? el : el.$el;
				}
			},
			getRef (selector) {
				return this.$refs[selector] ? this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector] : null
			},
			getRect (el) {
				return new Promise(resolve => {
					dom.getComponentRect(el, res => {
						resolve(res.size)
					})
				})
			},
			handleTap (e) {
				//开启禁用后才能触发点击事件
				if ( this.swiperBinding ) return
				if ( this.loading ) return
				if ( this.state ) {
					this.closeMenu()
					return
				}
				this.$emit('click', e)
			},
			handleRightMenuTap (index) {
				//右边菜单未打开无法点击
				if ( this.state != 'right' ) return
				this.$emit('leftClick', {
					index,
					detail: this.leftData[index]
				})
				if ( this.autoClose ) this.closeMenu()
			},
			handleLeftMenuTap (index) {
				//左边菜单未打开无法点击
				if ( this.state != 'left' ) return
				this.$emit('rightClick', {
					index,
					detail: this.leftData[index]
				})
				if ( this.autoClose ) this.closeMenu()
			}
		},
		watch: {
			rightDate () {
				this.$nextTick(() => {
					this.updateSize()
				})
			},
			leftData () {
				this.$nextTick(() => {
					this.updateSize()
				})
			}
		}
	}
</script>

<style>
</style>